﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using Sina.Altman.Weibo.SDK;
using System.Collections.Generic;
using Sina.Altman.Weibo.SDK.Objects;
using System.IO;
using Sina.Altman.Weibo.Tools;
using System.Text;

namespace Sina.Altman.Weibo.SDK
{
    public class StatusesRequest
    {
        static string token = Enviroment.Token;
        /// <summary>
        /// 获取公共信息流，返回值可能为null注意检查
        /// 获取操作为异步操作
        /// </summary>
        /// <param name="parameters">可加参数</param>
        /// <returns></returns>
        public static void GetRequest(StateType type,StatusesRequestData data, Action<object> callback)
        {
            var request = (HttpWebRequest)WebRequest.Create(new Uri(GetRequestUri(type,data),UriKind.Absolute));

            if (type == StateType.Update || type==StateType.Repost || type==StateType.Delete)
            {
                request.Method = "POST";
                request.ContentType = "application/x-www-form-urlencoded";
                request.BeginGetRequestStream((result) => RequestStreamCallback(result,type), new StatusesUserState() { Callback = callback, Request = request, RequestData = data });
            }
            else if (type == StateType.Upload)
            {
                request.Method = "POST";

                request.BeginGetRequestStream((result)=>RequestStreamCallback(result,type), new StatusesUserState() { Callback = callback, Request = request, RequestData = data });

            }
            else
            {
                request.Method = "GET";
                var inner = request.BeginGetResponse(ResponseCallback, new StatusesUserState() { Callback = callback, Request = request });
            }
        }

        /// <summary>
        /// 计算Post数据的长度
        /// </summary>
        /// <param name="result"></param>
        /// <param name="data"></param>
        /// <param name="type"></param>
        /// <param name="callback"></param>
        private static void RequestStreamCallback(IAsyncResult asyncResult, StateType type)
        {
            StatusesUserState state = (StatusesUserState)asyncResult.AsyncState;
            HttpWebRequest request = state.Request;
            Stream body = request.EndGetRequestStream(asyncResult);
            
            if (type == StateType.Upload)
            {
                PrepareFileData(state, request, body);
            }
            else if(type==StateType.Repost)
            {
                string postData = string.Empty;
                postData = "access_token=" + token + "&id=" + state.RequestData.WeiboID+Uri.EscapeDataString(state.RequestData.WeiboContent.Status);

                byte[] bytes = Encoding.UTF8.GetBytes(postData);
                body.Write(bytes,0,bytes.Length);
                body.Flush();
                body.Close();
            }
            else if (type == StateType.Delete)
            {
                string postData = string.Empty;
                postData = "access_token="+token+"&id="+state.RequestData.WeiboID;

                byte[] bytes = Encoding.UTF8.GetBytes(postData);
                body.Write(bytes,0,bytes.Length);
                body.Flush();
                body.Close();
            }
            else
            {
                string statusData = string.Empty;
                statusData = "access_token=" + token + "&status=" + Uri.EscapeDataString(state.RequestData.WeiboContent.Status);

                byte[] bytes = Encoding.UTF8.GetBytes(statusData);

                body.Write(bytes, 0, bytes.Length);

                body.Flush();

                body.Close();
            }

            request.BeginGetResponse((result) => ResponseCallback(result), state);
        }

        /// <summary>
        /// 准备上传的流
        /// </summary>
        /// <param name="state">包含上传的数据</param>
        /// <param name="request">发送请求</param>
        /// <param name="body">流</param>
        private static void PrepareFileData(StatusesUserState state, HttpWebRequest request, Stream body)
        {
            var boundary = string.Concat("--", Util.GenerateRndNonce());
            byte[] beginBoundary = Encoding.UTF8.GetBytes("\r\n--" + boundary + "\r\n");
            byte[] endBoundary = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");

            string paraTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
            string fileTemplate = "Content-Disposition: form-data; name=\"{0}\";filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";

            Files files = state.RequestData.WeiboContent.Files;

            request.ContentType = string.Concat("multipart/form-data; boundary=", boundary);

            using (MemoryStream memStream = new MemoryStream())
            {
                foreach (var item in state.RequestData.WeiboContent.Parameters)
                {
                    string value = item.Value;
                    byte[] bpara = Encoding.UTF8.GetBytes(string.Format(paraTemplate, item.Name, value));
                    memStream.Write(beginBoundary, 0, beginBoundary.Length);
                    memStream.Write(bpara, 0, bpara.Length);
                }

                foreach (var file in files.Items)
                {
                    byte[] bfile = Encoding.UTF8.GetBytes(string.Format(fileTemplate, file.Key, file.Value.FileName, file.Value.ContentType));
                    memStream.Write(beginBoundary, 0, beginBoundary.Length);
                    memStream.Write(bfile, 0, bfile.Length);

                    file.Value.WriteTo(memStream);

                    memStream.Write(endBoundary, 0, endBoundary.Length);
                }

                memStream.WriteTo(body);
                body.Flush();
                body.Close();
            }
        }

        /// <summary>
        /// 回调 
        /// </summary>
        /// <param name="result"></param>
        private static void ResponseCallback(IAsyncResult result)
        {
            var userState = result.AsyncState as StatusesUserState;
            
            try
            {
                var request = userState.Request as HttpWebRequest;
                var respone = (HttpWebResponse)request.EndGetResponse(result);

                var stream = respone.GetResponseStream();
                using (StreamReader reader = new StreamReader(stream))
                {
                    string jsonRes = reader.ReadToEnd();
                    if (!string.IsNullOrEmpty(jsonRes))
                    {
                        Status status = new Status(jsonRes);
                        if (null != userState.Callback)
                        {
                            userState.Callback(status);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                if (null != userState.Callback)
                    userState.Callback(e);
            }
        }

        /// <summary>
        /// 获取请求地址
        /// </summary>
        /// <param name="queryType"></param>
        /// <returns></returns>
        private static string GetRequestUri(StateType queryType,StatusesRequestData data)
        {
            if(string.IsNullOrEmpty(token))
                token = ISHelper.LoadSetting<string>(Constants.User_Access_Token_SR, string.Empty);
            string fullUri=string.Empty;

            switch (queryType)
            {
                case StateType.Public:
                    fullUri = Constants.STATUSES + "?source=" + Constants.APP_KEY + "&count=20" + "&access_token=" + token;
                    break;
                case StateType.Friends:
                    fullUri = Constants.FRIEDNS_TIMELINE + "?access_token=" + token;
                    break;
                case StateType.Update:
                    fullUri =Uri.EscapeUriString(Constants.UPDATE_ONE_STATUE + "?access_token=" + token+"&status="+data.WeiboContent.Status);
                    break;
                case StateType.Home:
                    fullUri = Constants.HOME_TIMELINE + "?access_token=" + token;
                    break;
                case StateType.Upload:
                    fullUri = Constants.UPLOAD_ONE_STATUE;
                    break;
                case StateType.AtMe:
                    fullUri = Constants.AT_ME + "?access_token=" + token;
                    break;
                case StateType.Repost:
                    fullUri = Constants.REPOST + "?access_token=" + token + "&id=" + data.WeiboID + "&status="+data.WeiboContent.Status;
                    break;
                case StateType.Usertimeline:
                    if (string.IsNullOrEmpty(data.UserID))
                        fullUri = Constants.USER_TIMELINT + "?access_token=" + token;
                    else
                        fullUri = Constants.USER_TIMELINT + "?access_token="+token + "&uid="+data.UserID;
                    break;
                case StateType.Delete:
                    fullUri = Constants.DELETE_STATUE;
                    break;
                default:
                    break;
            }

            return fullUri;
        }
    }

    public class StatusesUserState:UserState
    {
        public StatusesRequestData RequestData { get; set; }
    }

    public enum StateType
    {
        Public,
        Friends,
        Update,
        Home,
        Upload,
        AtMe,
        Repost,
        Delete,
        Usertimeline,
    }

    public class StatusesRequestData:RequestData
    {
        public WeiboContent WeiboContent { get; set; }
    }
}